After the tab view hides or shows (including when the chat window first opens, if...
[adiumx.git] / Plugins / Dual Window Interface / AIMessageTabViewItem.m
blobdff4e8609b0ac1e9ac92d8f496d9fa04e5c04b30
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
11  * Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License along with this program; if not,
14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
17 #import <Adium/AIContactControllerProtocol.h>
18 #import "AIMessageTabViewItem.h"
19 #import "AIMessageViewController.h"
20 #import "AIMessageWindowController.h"
21 #import "AIContactController.h"
22 #import "AIDualWindowInterfacePlugin.h"
23 #import <AIUtilities/AIImageAdditions.h>
24 #import <Adium/AIChat.h>
25 #import <Adium/AIListContact.h>
26 #import <Adium/AIServiceIcons.h>
27 #import <Adium/AIStatusIcons.h>
28 #import <Adium/AIPreferenceControllerProtocol.h>
30 #define BACK_CELL_LEFT_INDENT   -1
31 #define BACK_CELL_RIGHT_INDENT  3
32 #define LABEL_SIDE_PAD          0
34 @interface AIMessageTabViewItem (PRIVATE)
35 - (id)initWithMessageView:(AIMessageViewController *)inMessageView;
36 - (void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)labelRect;
37 - (NSSize)sizeOfLabel:(BOOL)computeMin;
38 - (NSAttributedString *)attributedLabelStringWithColor:(NSColor *)textColor;
39 - (void)chatParticipatingListObjectsChanged:(NSNotification *)notification;
40 - (void)chatStatusChanged:(NSNotification *)notification;
41 @end
43 @implementation AIMessageTabViewItem
46 + (AIMessageTabViewItem *)messageTabWithView:(AIMessageViewController *)inMessageView
48     return [[[self alloc] initWithMessageView:inMessageView] autorelease];
51 //init
52 - (id)initWithMessageView:(AIMessageViewController *)inMessageViewController
54         /* XXX - Warning! Setting self as the identifier also means that we are retaining ourselves!  Something _must_
55          * break us out of this infinite loop.  This happens in -[AIMesageWindowController removeTabViewItem:silent:].
56          */
57         if ((self = [super initWithIdentifier:self])) {
58                 messageViewController = [inMessageViewController retain];
59                 adium = [AIObject sharedAdiumInstance];
60                 windowController = nil;
62                 //Configure ourself for the message view
63                 [[adium notificationCenter] addObserver:self selector:@selector(chatStatusChanged:)
64                                                                                    name:Chat_StatusChanged
65                                                                                  object:[messageViewController chat]];
66                 [[adium notificationCenter] addObserver:self selector:@selector(chatAttributesChanged:)
67                                                                                    name:Chat_AttributesChanged
68                                                                                  object:[messageViewController chat]];  
69                 [[adium notificationCenter] addObserver:self selector:@selector(chatParticipatingListObjectsChanged:)
70                                                                                    name:Chat_ParticipatingListObjectsChanged
71                                                                                  object:[messageViewController chat]];
72                 [self chatStatusChanged:nil];
73                 [self chatParticipatingListObjectsChanged:nil];
74                 
75                 //Set our contents
76                 [self setView:[messageViewController view]];
77         }
78     return self;
82 - (void)dealloc
84     [[adium notificationCenter] removeObserver:self];
86         [tabViewItemImage release]; tabViewItemImage = nil;
87     [messageViewController release]; messageViewController = nil;
89     [super dealloc];
92 //Access to our message view controller
93 - (AIMessageViewController *)messageViewController
95     return messageViewController;
98 //Our chat
99 - (AIChat *)chat
101         return [messageViewController chat];
104 //Our containing window
105 - (void)setWindowController:(AIMessageWindowController *)inWindowController{
106         if (inWindowController != windowController) {
107                 [messageViewController messageViewWillLeaveWindowController:windowController];
109                 windowController = inWindowController;
111                 [messageViewController messageViewAddedToWindowController:windowController];
112         }
115 - (AIMessageWindowController *)windowController{
116         return windowController;
119 //Message View Delegate ----------------------------------------------------------------------
120 #pragma mark Message View Delegate
123  * @brief The list objects participating in our chat changed
124  */
125 - (void)chatParticipatingListObjectsChanged:(NSNotification *)notification
127         AIListObject    *listObject;
129         //Remove the old observer
130     [[adium notificationCenter] removeObserver:self name:ListObject_AttributesChanged object:nil];
132         //If there is a single list object for this chat, observe its attribute changes
133         if ((listObject = [messageViewController listObject])) {
134                 [[adium notificationCenter] addObserver:self
135                                                                            selector:@selector(listObjectAttributesChanged:)
136                                                                                    name:ListObject_AttributesChanged
137                                                                                  object:nil];
138                 
139         }
143 - (void)chatStatusChanged:(NSNotification *)notification
145     NSArray     *keys = [[notification userInfo] objectForKey:@"Keys"];
147     //If the display name changed, we resize the tabs
148     if (notification == nil || [keys containsObject:@"DisplayName"]) {
149                 id delegate = [[self tabView] delegate];
150                 //[delegate resizeTabForTabViewItem:self];
151                 
152         /* This should really be looked at and possibly a better method found.
153                  * This works and causes an automatic update to each open tab.  But it feels like a hack.
154                  * There is probably a more elegant method.  Something like [[[self tabView] delegate] redraw];  
155                  * I guess that's what this causes to happen, but the indirectness bugs me. It's obviously not the best solution,
156                  * but good enough for now.
157                  */
158         [delegate tabViewDidChangeNumberOfTabViewItems:[self tabView]];
159     } else if ([keys containsObject:@"UnviewedContent"]) {
160                 [self setValue:nil forKeyPath:@"objectCount"];
161         }
164 - (void)chatAttributesChanged:(NSNotification *)notification
166         NSArray         *keys = [[notification userInfo] objectForKey:@"Keys"];
167         
168         //Redraw if the icon has changed
169         if (keys == nil || [keys containsObject:@"Tab State Icon"]) {
170                 [[self windowController] updateIconForTabViewItem:self];
171                 [self setValue:nil forKeyPath:@"icon"];
172         }
175 - (void)listObjectAttributesChanged:(NSNotification *)notification
177         AIListObject *listObject = [notification object];
178         AIListContact *messageViewContact = [messageViewController listObject]; //Is the contact in the message view part of a metacontact?
179         
180         if (!listObject || (listObject == messageViewContact) || listObject == [messageViewContact parentContact]) {
181                 NSSet            *keys = [[notification userInfo] objectForKey:@"Keys"];
182                 
183                 //Redraw if the icon has changed
184                 if (!keys || [keys containsObject:@"Tab Status Icon"]) {
185                         [[self windowController] updateIconForTabViewItem:self];
186                         [self setValue:nil forKeyPath:@"icon"];
187                 }
188                 
189                 //If the list object's display name changed, we resize the tabs
190                 if (!keys || [keys containsObject:@"Display Name"]) {
191                         [self setLabel:[self label]];
192                 }
193         }
196 //Interface Container ----------------------------------------------------------------------
197 #pragma mark Interface Container
199 //Make this container active
200 - (void)makeActive:(id)sender
202     NSTabView   *tabView = [self tabView];
203     NSWindow    *window = [tabView window];
205     if ([tabView selectedTabViewItem] != self) {
206         [tabView selectTabViewItem:self]; //Select our tab
207     }
209     if (![window isKeyWindow] || ![window isVisible]) {
210         [window makeKeyAndOrderFront:nil]; //Bring our window to the front
211     }
214 //Close this container
215 - (void)close:(id)sender
217     [[self tabView] removeTabViewItem:self];
222 //Tab view item  ----------------------------------------------------------------------
223 #pragma mark Tab view item
225 //Called when our tab is selected
226 - (void)tabViewItemWasSelected
228     //Ensure our entry view is first responder
229     [messageViewController makeTextEntryViewFirstResponder];
233 - (NSString *)label
235         return ([[messageViewController chat] displayName]);
238 - (void)setIcon:(NSImage *)newIcon
240         //method does nothing; force the tab bindings to reload -icon
243 //Return the icon to be used for our tabs.  State gets first priority, then status.
244 - (NSImage *)icon
246         NSImage *image = [self stateIcon];
247         
248         //Multi-user chats won't have status icons
249         if (!image && ![messageViewController userListVisible]) image = [self statusIcon];
251         if (!image) image = [AIStatusIcons statusIconForUnknownStatusWithIconType:AIStatusIconTab direction:AIIconNormal];
253         return image;
256 //Status icon is the status of this contact (away, idle, online, stranger)
257 - (NSImage *)statusIcon
259         return [[[messageViewController chat] listObject] displayArrayObjectForKey:@"Tab Status Icon"];
262 //State icon is the state of the contact (Typing, unviewed content)
263 - (NSImage *)stateIcon
265         return [[messageViewController chat] displayArrayObjectForKey:@"Tab State Icon"];
268 - (NSImage *)image
270         return tabViewItemImage;
273 - (void)setLargeImage:(NSImage *)inImage
275         
278 - (NSImage *)largeImage
280         return [[[self chat] chatImage] imageByScalingToSize:NSMakeSize(48,48)];
283 //bindings methods for PSMTabBarControl
285 - (void)setObjectCount:(NSNumber *)number
287         //method does nothing; force the tab bindings to reload -objectCount
290 - (int)objectCount
292         //return 0 to disable the badge
293     return ([[[adium preferenceController] preferenceForKey:KEY_TABBAR_SHOW_UNREAD_COUNT group:PREF_GROUP_DUAL_WINDOW_INTERFACE] boolValue] ?
294                         [[self chat] unviewedContentCount] : 0);
297 - (void)tabViewDidChangeVisibility
299         [[self messageViewController] tabViewDidChangeVisibility];
302 @end